module Video_Image_Processor
(
    input   clk,    //cmos 像素时钟
    input   rst_n,  
    
    //预处理图像数据
    input        per_frame_vsync, //预图像数据列有效信号  
    input        per_frame_href,  //预图像数据行有效信号  
    input        per_frame_clken, //预图像数据输入使能效信号
    input [15:0] per_img_data, //输入RGB565数据

    input [8:0]    RED_H_MIN1  , //9'd0   
    input [8:0]    RED_H_MAX1  , //9'd48  
    input [8:0]    RED_H_MIN2  , //9'd310 
    input [8:0]    RED_H_MAX2  , //9'd360 
    input [7:0]    RED_V_MIN   ,
    input [7:0]    RED_V_MAX   ,
    input [8:0]    YELLOW_H_MIN, //9'd50  
    input [8:0]    YELLOW_H_MAX, //9'd75  
    input [7:0]    YELLOW_V_MIN   ,
    input [7:0]    YELLOW_V_MAX   ,
    input [8:0]    BLUE_H_MIN  , //9'd200  
    input [8:0]    BLUE_H_MAX  , //9'd274 
    input [7:0]    BLUE_V_MIN   ,
    input [7:0]    BLUE_V_MAX   , 
    input [7:0]    BLACK_V_MIN , //8'd0   
    input [7:0]    BLACK_V_MAX ,  //8'd70 
    
    //处理后的图像数据
    output       post_frame_vsync, //处理后的图像数据列有效信号  
    output       post_frame_href ,  //处理后的图像数据行有效信号  
    output       post_frame_clken, //处理后的图像数据输出使能效信号
    output [7:0] post_img_data   ,    //处理后的灰度数据    

    input  [1:0] color       
);

//parameter define 

// parameter RED_H_MIN1 =   9'd0   ;   
// parameter RED_H_MAX1 =   9'd48  ;
// parameter RED_H_MIN2 =   9'd310 ;
// parameter RED_H_MAX2 =   9'd360 ;
// parameter YELLOW_H_MIN = 9'd50  ; //50-55
// parameter YELLOW_H_MAX = 9'd75  ;
// parameter BLUE_H_MIN =   9'd200 ;
// parameter BLUE_H_MAX =   9'd274 ;
// parameter BLACK_V_MIN =  8'd0   ;
// parameter BLACK_V_MAX =  8'd70  ; //70-80

parameter RED    = 2'd0;
parameter YELLOW = 2'd1;
parameter BLUE   = 2'd2;
parameter BLACK  = 2'd3;

//wire define 
wire    [8:0]   hsv_h;
wire    [8:0]   hsv_s;
wire    [7:0]   hsv_v;
wire            post_hsv_vsync;
wire            post_hsv_href ;
wire            post_hsv_clken;
reg             key_value_d0;

//assign define

//*****************************************************
//**                    main code
//*****************************************************

RGB2HSV  u_RGB2HSV (
    .clk                     (clk          ),
    .reset_n                 (rst_n      ),
    //input signals
    .per_img_vsync           (per_frame_vsync),
    .per_img_href            (per_frame_href ),
    .per_img_valid           (per_frame_clken),
    .rgb_r                   ({per_img_data[15:11],3'b0}),
    .rgb_g                   ({per_img_data[10:5] ,2'b0}),
    .rgb_b                   ({per_img_data[4:0]  ,3'b0}),
    //output signals
    .post_img_vsync          (post_hsv_vsync),
    .post_img_href           (post_hsv_href ),
    .post_img_valid          (post_hsv_clken),
    .hsv_h                   (hsv_h),
    .hsv_s                   (hsv_s),
    .hsv_v                   (hsv_v)
);

reg            post_hsv_vsync_d0;
reg            post_hsv_href_d0 ;
reg            post_hsv_clken_d0;

//lag 1 clock
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        post_hsv_vsync_d0 <= 1'd0;
        post_hsv_href_d0  <= 1'd0;
        post_hsv_clken_d0 <= 1'd0;        
    end
    else begin
        post_hsv_vsync_d0 <= post_hsv_vsync;
        post_hsv_href_d0  <= post_hsv_href ;
        post_hsv_clken_d0 <= post_hsv_clken;  
    end
end

reg     [7:0]  post_hsv_data;

//颜色分类(输出是四通道)
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        post_hsv_data <= 1'd0;
    end
    else begin
        case (color)
            RED: begin
                if( ((hsv_v >= RED_V_MIN) && (hsv_v <= RED_V_MAX)) && 
                    (((hsv_h >= RED_H_MIN1) && (hsv_h <= RED_H_MAX1)) || 
                        ((hsv_h >= RED_H_MIN2) && (hsv_h < RED_H_MAX2))) )begin
                    post_hsv_data <= {8{1'b1}};
                end
                else begin
                    post_hsv_data <= 8'b0;
                end
            end
            BLUE: begin
                if((hsv_v >= BLUE_V_MIN) && (hsv_v <= BLUE_V_MAX) && 
                    (hsv_h >= BLUE_H_MIN) && (hsv_h <= BLUE_H_MAX))begin
                    post_hsv_data <= {8{1'b1}};
                end
                else begin
                    post_hsv_data <= 8'b0;
                end
            end
            BLACK: begin
                if((hsv_h > RED_H_MAX1) && (hsv_h < RED_H_MIN2) && 
                    (hsv_v >= BLACK_V_MIN) && (hsv_v <= BLACK_V_MAX))begin
                    post_hsv_data <= {8{1'b1}};
                end
                else begin
                    post_hsv_data <= 8'b0;
                end
            end
            YELLOW: begin
                if((hsv_v >= YELLOW_V_MIN) && (hsv_v <= YELLOW_V_MAX) && 
                    (hsv_h >= YELLOW_H_MIN) && (hsv_h <= YELLOW_H_MAX))begin
                    post_hsv_data <= {8{1'b1}};
                end
                else begin
                    post_hsv_data <= 8'b0;
                end
            end
            default: post_hsv_data <= post_hsv_data;
        endcase
    end
end

wire        post_erosion_vsync;
wire        post_erosion_href ;
wire        post_erosion_clken;
wire [7:0]  post_erosion_data ;

//erosion_1
erosion_dilation 
#(
    .thresh (6)
)
erosion (
    .clk                     ( clk           ),
    .rst_n                   ( rst_n         ),

    .pe_frame_vsync          (post_hsv_vsync_d0),
    .pe_frame_href           (post_hsv_href_d0 ),
    .pe_frame_clken          (post_hsv_clken_d0),
    .pe_img_Y                (post_hsv_data    ),

    .pos_frame_vsync         (post_erosion_vsync),
    .pos_frame_href          (post_erosion_href ),
    .pos_frame_clken         (post_erosion_clken),
    .pos_img_Y               (post_erosion_data )
);

wire        post_dilation_vsync;
wire        post_dilation_href ;
wire        post_dilation_clken;
wire [7:0]  post_dilation_data ;

//dilation
erosion_dilation 
#(
    .thresh (3)
)
dilation (
    .clk                     ( clk           ),
    .rst_n                   ( rst_n         ),

    .pe_frame_vsync          (post_erosion_vsync),
    .pe_frame_href           (post_erosion_href ),
    .pe_frame_clken          (post_erosion_clken),
    .pe_img_Y                (post_erosion_data ),

    .pos_frame_vsync         (post_dilation_vsync),
    .pos_frame_href          (post_dilation_href ),
    .pos_frame_clken         (post_dilation_clken),
    .pos_img_Y               (post_dilation_data )
);

//erosion_2
erosion_dilation 
#(
    .thresh (8)
)
erosion_2 (
    .clk                     ( clk           ),
    .rst_n                   ( rst_n         ),

    .pe_frame_vsync          (post_dilation_vsync),
    .pe_frame_href           (post_dilation_href ),
    .pe_frame_clken          (post_dilation_clken),
    .pe_img_Y                (post_dilation_data ),

    .pos_frame_vsync         (post_frame_vsync),
    .pos_frame_href          (post_frame_href ),
    .pos_frame_clken         (post_frame_clken),
    .pos_img_Y               (post_img_data   )
);

endmodule 